﻿using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Interactivity;
using System.Windows.Controls.Primitives;
using WP7Contrib.View.Controls.Extensions;

namespace WP7Contrib.View.Controls.Behaviors
{
    /// <summary>
    /// This behaviour, when associated with an AutoCompleteBox, animates the
    /// items within the auto-complete list, causing them to slide down into view.
    /// </summary>
    public class AutoCompleteSlideBehaviour : Behavior<AutoCompleteBox>
    {
        private ListBox _popUpListbox;

        private Popup _popup;

        protected override void OnAttached()
        {
            base.OnAttached();

            // locate the listBox, if this fails, the AutoCOmpleteBox is not loaded,
            // so try again after the Loaded event.
            if (!TryFindListBox())
            {
                RoutedEventHandler onLoaded = null;
                onLoaded = (s, e) =>
                    {
                        TryFindListBox();
                        AssociatedObject.Loaded -= onLoaded;
                    };
                AssociatedObject.Loaded += onLoaded;
            }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            _popup.Opened -= Popup_Opened;
        }

        /// <summary>
        /// Tries to locate the Listbox within the auto-completes Popup.
        /// </summary>
        private bool TryFindListBox()
        {
            // locate the auto-complete  popup
            _popup = AssociatedObject.Descendants<Popup>().SingleOrDefault() as Popup;
            if (_popup == null)
                return false;

            _popup.Opened += Popup_Opened;

            // locate the ListBox
            _popUpListbox = _popup.Child.Descendants<ListBox>().SingleOrDefault() as ListBox;
            return true;
        }

        /// <summary>
        /// Handle the Opened even on the Popup in order to animate the contents
        /// </summary>
        private void Popup_Opened(object sender, System.EventArgs e)
        {
            if (_popUpListbox.Items.Count == 0)
                return;

            // an action which fires the required animation for each element
            Action fireAnimations = () =>
            {
                // locate all the ListBoxItems
                var itemContainers = _popUpListbox.Items
                    .Select(i => _popUpListbox.ItemContainerGenerator.ContainerFromItem(i))
                    .Where(i => i != null)
                    .Cast<ListBoxItem>();

                // animate each item
                double startTime = 0;
                foreach (var listBoxItem in itemContainers)
                {
                    // add a render transform that offsets the element
                    var trans = new TranslateTransform()
                       {
                           Y = -50
                       };
                    listBoxItem.RenderTransform = trans;
                    listBoxItem.Opacity = 0.0;

                    var sb = new Storyboard();
                    sb.BeginTime = TimeSpan.FromMilliseconds(startTime);
                    sb.Children.Add(TiltBehaviour.CreateAnimation(null, 0, 0.2, "Y", trans));
                    sb.Children.Add(TiltBehaviour.CreateAnimation(null, 1, 0.5, "Opacity", listBoxItem));
                    sb.Begin();

                    startTime += 100;
                }
            };

            // check if the item container for the first item has been generated
            if (_popUpListbox.ItemContainerGenerator.ContainerFromIndex(0) == null)
            {
                // if not, wait for the next LayoutUpdated event
                EventHandler updateHandler = null;
                updateHandler = (s, e2) =>
                {
                    fireAnimations();
                    _popUpListbox.LayoutUpdated -= updateHandler;
                };
                _popUpListbox.LayoutUpdated += updateHandler;
            }
            else
            {
                // otherwise, fire the animations now
                fireAnimations();
            }
        }
    }
}
